/**
 * 
 */
package org.jenkon.commons.lang.builder;

import java.util.Comparator;

import org.jenkon.commons.lang.Resetable;

/**
 * 
 * @author Jens Konopka
 * 
 */
public class CompareToBuilder implements Resetable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2348598412229051097L;

	private int value = 0;

	/**
	 * <p>
	 * Compare the left {@link Object} with the right {@link Object}.
	 * </p>
	 * 
	 * @param left the left {@link Object} to compare
	 * @param right the right {@link Object} to compare
	 * @return the currently instance of this {@link CompareToBuilder}
	 * @see #append(Object, Object, Comparator)
	 */
	public CompareToBuilder append(final Object left, final Object right) {
		return append(left, right, null);
	}

	/**
	 * <p>
	 * Compare the left array with objects with the right array with objects.
	 * </p>
	 * 
	 * @param left left array with objects to compare
	 * @param right right array with objects to compare
	 * @return the currently instance of this {@link CompareToBuilder}
	 * @see #append(Object[], Object[], Comparator)
	 */
	public CompareToBuilder append(final Object[] left, final Object[] right) {
		return append(left, right, null);
	}

	/**
	 * <p>
	 * Compare the left array with objects with the right array with objects.
	 * </p>
	 * <p>
	 * If the {@link Comparator} is <code>null</code> then cast the left {@link Object} to
	 * {@link Comparable} and call {@link Comparable#compareTo(Object)}, else the {@link Comparator}
	 * is not <code>null</code> then compare the objects with the
	 * {@link Comparator#compare(Object, Object)}.
	 * </p>
	 * 
	 * @param left left array with objects to compare
	 * @param right right array with objects to compare
	 * @param comparator {@link Comparator} to compare.
	 * @return the currently instance of this {@link CompareToBuilder}
	 */
	public CompareToBuilder append(final Object[] left, final Object[] right, final Comparator<Object> comparator) {

		if (value != 0) {
			return this;
		}

		if (left == right) {
			return this;
		}

		if (left == null) {
			value = -1;
			return this;
		}

		if (right == null) {
			value = +1;
			return this;
		}

		if (left.length != right.length) {
			value = (left.length < right.length) ? -1 : +1;
			return this;
		}

		for (int i = 0; i < left.length && value == 0; i++) {
			append(left[i], right[i], comparator);
		}

		return this;

	}

	/**
	 * <p>
	 * Compare the left {@link Object} with the right {@link Object}.
	 * </p>
	 * <p>
	 * If the {@link Comparator} is <code>null</code> then cast the left {@link Object} to
	 * {@link Comparable} and call {@link Comparable#compareTo(Object)}, else the {@link Comparator}
	 * is not <code>null</code> then compare the objects with the
	 * {@link Comparator#compare(Object, Object)}.
	 * </p>
	 * 
	 * @param left the left {@link Object} to compare
	 * @param right the right {@link Object} to compare
	 * @param comparator {@link Comparator} to compare.
	 * @return the currently instance of this {@link CompareToBuilder}
	 * @throws ClassCastException if the is not a {@link Comparable}
	 * @see Comparable#compareTo(Object)
	 * @see Comparator#compare(Object, Object)
	 */
	public CompareToBuilder append(final Object left, final Object right, final Comparator<Object> comparator) {

		if (value != 0) {
			return this;
		}

		if (left == right) {
			return this;
		}

		if (left == null) {
			value = -1;
			return this;
		}

		if (right == null) {
			value = +1;
			return this;
		}

		value = compare(left, right, comparator);

		return this;
	}

	/**
	 * @param left the left {@link Object} to compare
	 * @param right the right {@link Object} to compare
	 * @param comparator {@link Comparator} to compare. If the {@link Comparator} is
	 *        <code>null</code> the cast the left {@link Object} to {@link Comparable} and call
	 *        {@link Comparable#compareTo(Object)}.
	 * @return result of comparing
	 * @throws ClassCastException if the is not a {@link Comparable}
	 * @see Comparable#compareTo(Object)
	 * @see Comparator#compare(Object, Object)
	 */
	@SuppressWarnings("unchecked")
	private int compare(final Object left, final Object right, final Comparator<Object> comparator) {
		if (comparator == null) {
			return ((Comparable<Object>) left).compareTo(right);
		}
		return comparator.compare(left, right);
	}

	/**
	 * @return get the {@link #value}
	 */
	public int toComparison() {
		return value;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.Resetable#reset()
	 */
	public void reset() {
		value = 0;
	}

}
